Skip to content

v0.7.19: newsletter, contact, careers#5318

Merged
waleedlatif1 merged 3 commits into
mainfrom
staging
Jul 1, 2026
Merged

v0.7.19: newsletter, contact, careers#5318
waleedlatif1 merged 3 commits into
mainfrom
staging

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

…5317)

- Drop the #F8F8F8 canvas to a clean white background (body + outer wrapper).
- Replace Discord with LinkedIn in the footer social row.
- Swap the low-res header logo for the full-res sim logotype.
* feat(landing): reintroduce /contact page styled like /demo

- Restore the /contact page (removed in #5181) with a two-column layout
  mirroring /demo: value prop + trusted-by logos on the left, a message
  form card on the right, on the platform light tokens and chip components
- Restore the contact contract, /api/contact route (rate-limit, honeypot,
  Turnstile, help-inbox notification + visitor confirmation), now fully
  contract-bound via parseRequest
- Add a useSubmitContact React Query mutation hook
- Link Contact from the footer Resources column and add it to the sitemap

* fix(contact): server-authoritative captcha + review fixes

- Make captcha server-authoritative: drop the client-trusted captchaUnavailable
  flag; a valid Turnstile token is the only way past the stricter fallback
  bucket, so callers can't opt out of the challenge
- Re-execute the Turnstile widget on every submit (incl. after expiry) instead
  of falling into the no-captcha path once the token expires
- Reset the pre-submit gate on mutation settle so rapid double-clicks can't fire
  a duplicate /api/contact request
- Map only feature_request to its email type; every other topic resolves to a
  General Inquiry confirmation so support requests aren't labeled bug reports
- Drop the confirmation-email promise from the success copy (it's best-effort)
- Collapse the duplicated no-captcha rate-limit branch; hoist shared response
  constants; read the Turnstile site key as a module constant

* fix(contact): drop redundant Turnstile hostname pin

The Turnstile site key is already domain-bound in Cloudflare, so pinning
expectedHostname to the marketing SITE_URL (www.sim.ai) only rejected valid
tokens issued on self-hosted, preview, and apex-vs-www hosts. Remove the pin
and rely on Cloudflare's own domain binding.

* fix(contact): fail closed on the no-captcha rate-limit backstop

checkRateLimitDirect fails open on limiter-storage errors so a limiter outage
never takes down normal traffic. But the contact route's no-captcha bucket is
the only throttle on token-less submits, so a fail-open there let uncaptcha'd
requests reach the email path unthrottled during an outage.

- Add an opt-in { failClosed } option to checkRateLimitDirect; default behavior
  (fail open) is unchanged
- Use failClosed on the contact no-captcha backstop so an unenforceable limit
  rejects instead of admitting
- Cover both fail-open and fail-closed paths with tests

* refactor(contact): TSDoc over inline comments

Move the captcha-design rationale into the route handler's TSDoc and drop the
inline body/JSX comments, per the project's TSDoc-only comment convention.
* feat(careers): careers page backed by the Ashby job board

* fix(careers): harden Ashby parsing and filter edge cases from review

- validate jobUrl as http(s) only; drop postings with unsafe URLs
- validate postings individually so one bad row can't empty the board
- namespace the all-filter sentinel to avoid colliding with real values
- dedupe the job metadata line (fixes duplicate React keys / Remote·Remote)
- parse filters server-side so deep-linked views don't flash unfiltered

* fix(careers): filter-aware empty state; drop inline comments

- JobGroups owns its empty copy via a filtersActive flag, so the server
  fallback and client board render identical, correct empty messaging
  (no-open-roles vs no-matching-filters)
- convert remaining inline comments to TSDoc
@vercel

vercel Bot commented Jul 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jul 1, 2026 8:26am

Request Review

@cursor

cursor Bot commented Jul 1, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
New public /api/contact sends email and handles captcha/rate limits; mistakes could affect spam handling or deliverability, though protections are layered.

Overview
Adds on-site /careers and /contact landing pages and wires them through nav, footer, and the sitemap (Careers moves from external Ashby to /careers; Contact is new).

Careers loads open roles from Ashby’s public API (getAshbyJobs), server-renders the full list for SEO, and hydrates a Team/Location board with shareable ?team= / ?location= filters (nuqs). The Suspense fallback applies the same server-side filters so deep links don’t flash unfiltered listings.

Contact mirrors the demo layout: chip form, client validation via shared Zod contract, invisible Turnstile, honeypot, and POST /api/contact that rate-limits per IP, verifies captcha (stricter bucket when captcha can’t be verified, with failClosed on the limiter backstop), emails help@, and sends a visitor confirmation.

The July broadcast email template switches to a white canvas and replaces the footer Discord link with LinkedIn.

Reviewed by Cursor Bugbot for commit 2393b72. Configure here.

@waleedlatif1 waleedlatif1 merged commit 6e426f8 into main Jul 1, 2026
24 checks passed
@greptile-apps

greptile-apps Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds new public landing surfaces and updates the newsletter. The main changes are:

  • New /careers page backed by Ashby job postings.
  • New /contact page with a public contact API route.
  • Footer and sitemap links for careers and contact.
  • Newsletter background, logo, and social-link updates.
  • Rate-limiter support for fail-closed direct checks.

Confidence Score: 5/5

This looks safe to merge after checking the optional Ashby row-handling cleanup.

  • No blocking issues found in the changed code.
  • The contact API uses the existing client error path for non-success responses.
  • The careers page can skip Ashby rows with missing hosted URLs, but the page still renders and logs skipped rows.

apps/sim/lib/ashby/jobs.ts

Important Files Changed

Filename Overview
apps/sim/app/api/contact/route.ts Adds the public contact submission endpoint with validation, Turnstile fallback handling, rate limiting, and email dispatch.
apps/sim/lib/api/contracts/contact.ts Defines the shared contact request and response contract with field bounds and email-header character checks.
apps/sim/app/(landing)/contact/components/contact-form/contact-form.tsx Adds the client contact form with shared validation, Turnstile execution, honeypot payload, and mutation-driven success/error UI.
apps/sim/lib/ashby/jobs.ts Adds the Ashby job-board fetcher, validation, normalization, URL scheme restriction, and posting sort order.
apps/sim/app/(landing)/careers/components/job-board/job-board.tsx Adds the URL-backed careers filter UI and renders grouped job postings.
apps/sim/app/(landing)/careers/search-params.ts Adds shared nuqs parsers and server cache for careers team and location filters.
apps/sim/lib/core/rate-limiter/rate-limiter.ts Adds an optional fail-closed mode for direct token-bucket checks while keeping the default fail-open behavior.

Comments Outside Diff (1)

  1. apps/sim/lib/ashby/jobs.ts, line 1326 (link)

    P2 Missing Job URLs Drop Roles

    When Ashby returns a listed posting without jobUrl, this required schema field makes that row fail validation and the board skips it. Ashby omits fields that are missing, so a valid listed role can disappear from /careers, and if every listed role is missing this field the page shows “No open roles right now.”

Reviews (1): Last reviewed commit: "feat(careers): careers page backed by th..." | Re-trigger Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant